home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 4
/
Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso
/
Pearls
/
dev
/
Oberon
/
OberonV4
/
system
/
Hex.Mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1990-01-01
|
34KB
|
1,026 lines
Syntax10.Scn.Fnt
Syntax10b.Scn.Fnt
Syntax10i.Scn.Fnt
MODULE Hex; (* Hansjoerg Buchser; 25. 2. 1994 / MH 9 MAR 1994 *)
IMPORT Texts, TextFrames, Viewers, Display, Files, Oberon, MenuViewers, Fonts, SYSTEM, Input;
CONST StandardMenu = "System.Close System.Copy System.Grow Hex.Search Hex.StoreText Hex.Store ";
updateByte = 0; changeFont = 1; (* message id *)
ord0 = 48; ordA = 65; orda = 97; (* ASCII values *)
hexdX = 3; dY = 3; (* cursor overlapping *)
begOfLine = 20; barW = 13; (* x-coords in Frame *)
colspace = 3; adrlen = 6; (* number of chars *)
number = 16; (* number of bytes per line *)
DefaultFont = "Courier12.Scn.Fnt";
MR = 0; MM = 1; ML = 2;
fgd = Display.white; bgd = Display.black;
TYPE
CursorCoord = POINTER TO CursorCoordDesc;
CursorCoordDesc = RECORD X, W : INTEGER END;
Model = POINTER TO ModelDesc;
ModelDesc = RECORD name : ARRAY 32 OF CHAR; file : Files.File END;
Frame = POINTER TO FrameDesc;
FrameDesc = RECORD (Display.FrameDesc)
virgin, hasCursor : BOOLEAN;
cursor1, cursor2 : CursorCoord; (* primary, secondary cursor *)
cursorY : INTEGER;
cursorBytePos : LONGINT;
model : Model;
org, len : LONGINT
END;
UpdateMsg = RECORD (Display.FrameMsg)
id : INTEGER;
file : Files.File;
pos : LONGINT;
ch : CHAR
END;
CursorMsg = RECORD (Display.FrameMsg)
pos : LONGINT;
file : Files.File;
END;
font : Fonts.Font;
fontwidth, fontheight, hmin, hmax, amin, amax : INTEGER; (* display variables *)
cursorH, greybar1, greybar2, greybar3 : INTEGER;
hexcurs, asccurs : CursorCoord;
nextline : ARRAY number OF CHAR; (* output variables *)
R : Files.Rider;
W : Texts.Writer;
res : INTEGER;
(* ____________________________ HexFrames-Part of Module __________________________ *)
(* ______________________________ some auxiliary functions ____________________________ *)
PROCEDURE Cap(ch : CHAR) : CHAR;
BEGIN
CASE ch OF "a".."z" : RETURN CAP(ch) ELSE RETURN ch END;
END Cap;
PROCEDURE DecToHex(d : LONGINT) : CHAR;
BEGIN
IF d < 10 THEN d := d + ord0 ELSE d := d + ordA - 10 END;
RETURN CHR(d)
END DecToHex;
PROCEDURE HexToDec(ch : CHAR) : INTEGER;
BEGIN
CASE ch OF "A".."F" : RETURN ORD(ch) - ordA + 10
| "a".."f" : RETURN ORD(ch) - orda + 10
| "0".."9" : RETURN ORD(ch) - ord0
ELSE RETURN -1
END
END HexToDec;
PROCEDURE ReadableChar(ch : CHAR) : CHAR;
BEGIN
CASE ORD(ch) OF
32..126, 128..149, 155 : RETURN ch
ELSE RETURN "."
END
END ReadableChar;
(* ______________________________ init procedure ____________________________ *)
PROCEDURE InitDisplayVars;
VAR dx, x, y, w, h : INTEGER;
p : Display.Pattern;
BEGIN
Display.GetChar(font.raster, "0", dx, x, y, w, h, p);
fontwidth := dx;
fontheight := font.height + 1;
hmin := begOfLine + (adrlen + colspace)*fontwidth;
hmax := hmin + (number*3 - 1)*fontwidth;
amin := hmax + colspace*fontwidth;
amax := amin + number*fontwidth;
greybar1 := hmin + (hmax - hmin - fontwidth) DIV 4;
greybar2 := hmin + (hmax - hmin) DIV 2;
greybar3 := hmax - (hmax - hmin - fontwidth) DIV 4;
NEW(hexcurs); hexcurs.W := 2*fontwidth + hexdX;
NEW(asccurs); asccurs.W := fontwidth;
cursorH := fontheight
END InitDisplayVars;
(* ______________________________ coord conversion ____________________________ *)
PROCEDURE GetLine(F : Frame; Y : INTEGER; VAR line : INTEGER);
BEGIN
IF Y >= F.Y THEN
line := (F.Y + F.H - Y - dY) DIV fontheight;
IF (line + 1)*fontheight >= F.H - dY THEN DEC(line) END;
IF line < 0 THEN line := 0 END
ELSE
line := (F.H - dY) DIV fontheight - 1
END
END GetLine;
PROCEDURE GetOffset(F : Frame; X : INTEGER; VAR off : INTEGER);
BEGIN
IF (hmin <= X - F.X) & (X - F.X <= hmax) THEN
off := (X - F.X - hmin + fontwidth DIV 2) DIV (3*fontwidth)
ELSIF (amin <= X - F.X) & (X - F.X <= amax) THEN
off := (X - F.X - amin) DIV fontwidth
ELSE
off := -1
END
END GetOffset;
PROCEDURE GetX(F : Frame; pos : LONGINT; VAR hX, aX : INTEGER);
BEGIN
IF pos < F.len THEN
DEC(pos, F.org);
pos := pos MOD number;
hX := F.X + hmin + SHORT(pos)*3*fontwidth;
aX := F.X + amin + SHORT(pos)*fontwidth
ELSE
hX := -1; aX := -1
END
END GetX;
PROCEDURE GetY(F : Frame; pos : LONGINT; VAR Y : INTEGER);
BEGIN
IF pos < F.len THEN
DEC(pos, F.org);
pos := pos DIV number;
Y := F.Y + F.H - (SHORT(pos) + 1)*fontheight
ELSE
Y := -1
END
END GetY;
(* ______________________________ display support ____________________________ *)
PROCEDURE WriteBang(F : Frame);
VAR R : Texts.Reader; V : Viewers.Viewer; T : Texts.Text; ch : CHAR;
BEGIN
V := Viewers.This(F.X, F.Y);
IF (V IS MenuViewers.Viewer) & (V.dsc IS TextFrames.Frame) THEN
T := V.dsc(TextFrames.Frame).text;
IF T.len > 0 THEN Texts.OpenReader(R, T, T.len - 1); Texts.Read(R, ch) ELSE ch := 0X END;
IF ch # "!" THEN Texts.Write(W, "!"); Texts.Append(T, W.buf) END
END
END WriteBang;
PROCEDURE DeleteBang(F : Frame);
VAR R : Texts.Reader; V : Viewers.Viewer; T : Texts.Text; ch : CHAR;
BEGIN
V := Viewers.This(F.X, F.Y);
IF (V IS MenuViewers.Viewer) & (V.dsc IS TextFrames.Frame) THEN
T := V.dsc(TextFrames.Frame).text;
IF T.len > 0 THEN Texts.OpenReader(R, T, T.len - 1); Texts.Read(R, ch) ELSE ch := 0X END;
IF ch = "!" THEN Texts.Delete(T, T.len - 1, T.len) END
END
END DeleteBang;
PROCEDURE InvertCursor(F : Frame);
BEGIN
IF (F.X < F.cursor1.X) & (F.cursor1.X + F.cursor1.W < F.X + F.W) &
(F.Y < F.cursorY) & (F.cursorY + cursorH <= F.Y + F.H) THEN
F.hasCursor := ~F.hasCursor;
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConst(fgd, F.cursor1.X, F.cursorY, F.cursor1.W, cursorH, Display.invert);
Display.ReplConstC(F, fgd, F.cursor2.X, F.cursorY, F.cursor2.W, 2, Display.invert)
END
END InvertCursor;
PROCEDURE RemoveCursor(F : Frame);
BEGIN
IF F.hasCursor THEN
InvertCursor(F);
F.cursorBytePos := -1
END
END RemoveCursor;
PROCEDURE DrawCursor(F : Frame);
BEGIN
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConstC(F, fgd, F.cursor1.X, F.cursorY, F.cursor1.W, cursorH, Display.invert);
Display.ReplConstC(F, fgd, F.cursor2.X, F.cursorY, F.cursor2.W, 2,Display.invert)
END DrawCursor;
PROCEDURE SetCursor(F : Frame; X, Y : INTEGER);
VAR offset, line : INTEGER;
pos : LONGINT;
BEGIN
GetOffset(F, X, offset);
GetLine(F, Y, line);
pos := LONG(line)*number + offset + F.org;
IF pos < F.len THEN
IF F.cursor1 = hexcurs THEN
GetX(F, pos, F.cursor1.X, F.cursor2.X);
DEC(F.cursor1.X, hexdX DIV 2)
ELSE (* F.cursor1 = asccurs *)
GetX(F, pos, F.cursor2.X, F.cursor1.X);
DEC(F.cursor2.X, hexdX DIV 2)
END;
GetY(F, pos, F.cursorY);
DEC(F.cursorY, dY);
F.cursorBytePos := pos;
InvertCursor(F)
END
END SetCursor;
(* ______________________________ draw file content ____________________________ *)
PROCEDURE ShowChar (F : Frame; ch : CHAR; VAR X : INTEGER; Y : INTEGER);
VAR dx, x, y, w, h : INTEGER; p : Display.Pattern;
BEGIN
IF (F.X < X) & (X + fontwidth < F.X + F.W) & (F.Y + dY < Y) & (Y + fontheight <= F.Y + F.H) THEN
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.GetChar(font.raster, ch, dx, x, y, w, h, p);
Display.CopyPattern(fgd, p, X+x, Y+y, Display.replace);
INC(X, dx)
END
END ShowChar;
PROCEDURE ShowSpaces (F : Frame; num : INTEGER; VAR X : INTEGER; Y : INTEGER);
VAR i : INTEGER;
BEGIN i := 0;
WHILE i < num DO ShowChar(F, " ", X, Y); INC(i) END
END ShowSpaces;
PROCEDURE ShowAddress(F : Frame; pos : LONGINT; VAR X : INTEGER; Y : INTEGER);
VAR div : LONGINT;
BEGIN
div := 0100000H;
REPEAT
ShowChar(F, DecToHex(pos DIV div), X, Y);
pos := pos MOD div;
div :=ASH(div, -4);
UNTIL div = 0;
END ShowAddress;
PROCEDURE ShowHexPart(F : Frame; max : INTEGER; VAR X : INTEGER; Y : INTEGER);
VAR i : INTEGER;
BEGIN
i := 0;
WHILE i < max DO
ShowChar(F, DecToHex(ASH(ORD(nextline[i]), -4)), X, Y);
ShowChar(F, DecToHex(ORD(nextline[i]) MOD 16), X, Y);
ShowSpaces(F, 1, X, Y);
INC(i)
END;
ShowSpaces(F, (number-i)*3, X, Y)
END ShowHexPart;
PROCEDURE ShowAscPart(F : Frame; max : INTEGER; VAR X : INTEGER; Y : INTEGER);
VAR i : INTEGER;
BEGIN
i := 0;
WHILE i < max DO
ShowChar(F, ReadableChar(nextline[i]), X, Y);
INC(i)
END
END ShowAscPart;
PROCEDURE ShowLine(F : Frame; Y, nr : INTEGER; adr : LONGINT);
VAR X : INTEGER;
BEGIN
X := F.X + begOfLine;
ShowAddress(F, adr, X, Y);
ShowSpaces(F, colspace, X, Y);
ShowHexPart(F, nr, X, Y);
ShowSpaces(F, colspace-1, X, Y);
ShowAscPart(F, nr, X, Y)
END ShowLine;
PROCEDURE DrawGreyBars(F : Frame);
VAR Y, H, line : INTEGER; help : LONGINT;
BEGIN
GetLine(F, F.Y + 1, line);
help := F.len - F.org;
IF (line + 1)*number > help THEN (* eof visible *)
Y := F.Y + F.H - SHORT((help - 1) DIV number + 1)*fontheight - dY;
H := SHORT((help - 1) DIV number + 1)*fontheight
ELSE (* eof not visible *)
Y := F.Y + F.H - (line + 1)*fontheight - dY;
H := (line + 1)*fontheight
END;
IF (F.H - 1 - dY) DIV fontheight > 0 THEN (* at least one line visible *)
Display.ReplPattern(fgd, Display.grey1, F.X + greybar1, Y, 1, H, Display.replace);
Display.ReplPattern(fgd, Display.grey1, F.X + greybar2, Y, 1, H, Display.replace);
Display.ReplPattern(fgd, Display.grey1, F.X + greybar3, Y, 1, H, Display.replace)
END
END DrawGreyBars;
PROCEDURE DrawClip(F : Frame);
CONST clipW = 8; clipH = 2;
VAR Y : INTEGER;
BEGIN
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConst(bgd, F.X + 1, F.Y, barW - 2, F.H, Display.replace);
Y := F.Y + F.H - clipH - SHORT((F.H - clipH)*F.org DIV F.len);
Display.ReplConst(fgd, F.X + 1, Y, clipW, clipH, Display.replace)
END DrawClip;
PROCEDURE Draw(F : Frame; Y, maxY : INTEGER; pos : LONGINT);
VAR X : INTEGER;
rest : INTEGER;
BEGIN
DEC(Y, fontheight);
IF F.len > 0 THEN
Files.Set(R, F.model.file, pos);
Files.ReadBytes(R, nextline, number);
WHILE ~R.eof & (Y > maxY) DO
ShowLine(F, Y, number, Files.Pos(R) - number);
DEC(Y, fontheight);
Files.ReadBytes(R, nextline, number)
END;
rest := number - SHORT(R.res);
IF (Y > maxY) & (rest > 0) THEN
ShowLine(F, Y, rest, Files.Pos(R)-rest)
END;
DrawClip(F)
END
END Draw;
PROCEDURE DrawFrame(F : Frame);
VAR line : INTEGER;
BEGIN
RemoveCursor(F);
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConst(bgd, F.X, F.Y, F.W, F.H, Display.replace);
Display.ReplConst(fgd, F.X+barW, F.Y, 1, F.H, Display.replace);
Draw(F, F.Y + F.H, F.Y + dY, F.org);
DrawGreyBars(F)
END DrawFrame;
(* ______________________________ update procedures ____________________________ *)
PROCEDURE AscUpdateByte(F : Frame; ch : CHAR);
BEGIN
Files.Set(R, F.model.file, F.cursorBytePos);
Files.Write(R, ch)
END AscUpdateByte;
PROCEDURE HexUpdateByte(F : Frame; ord : INTEGER);
VAR help : CHAR;
BEGIN
Files.Set(R, F.model.file, F.cursorBytePos);
Files.Read(R, help);
help := CHR(SYSTEM.LSH(ORD(help), 4) + ord);
Files.Set(R, F.model.file, F.cursorBytePos);
Files.Write(R, help)
END HexUpdateByte;
PROCEDURE Update(F : Frame; pos : LONGINT; ch : CHAR);
VAR hX, aX, Y : INTEGER;
BEGIN
GetX(F, pos, hX, aX);
GetY(F, pos, Y);
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConstC(F, bgd, hX - hexdX DIV 2, Y - dY, hexcurs.W, cursorH, Display.replace);
ShowChar(F, DecToHex(ASH(ORD(ch), -4)), hX, Y);
ShowChar(F, DecToHex(ORD(ch) MOD 16), hX, Y);
Display.ReplConstC(F, bgd, aX, Y - dY, asccurs.W, cursorH, Display.replace);
ShowChar(F, ReadableChar(ch), aX, Y)
END Update;
PROCEDURE SendUpdateMsg(F : Frame);
VAR M : UpdateMsg; ch : CHAR;
BEGIN
Files.Set(R, F.model.file, F.cursorBytePos);
Files.Read(R, ch);
M.id := updateByte; M.file := F.model.file; M.ch := ch; M.pos := F.cursorBytePos;
Viewers.Broadcast(M)
END SendUpdateMsg;
(* ______________________________ scrolling procedures ____________________________ *)
PROCEDURE ScrollFrame (F : Frame; pos : LONGINT; line : INTEGER);
VAR H, d, maxline : INTEGER;
BEGIN
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
GetLine(F, F.Y + 1, maxline);
d := F.H - (maxline + 1)*fontheight;
IF (F.org < pos) & (pos <= F.org + maxline*number) THEN
(* scroll down *)
RemoveCursor(F);
H := F.H - line*fontheight - d;
F.org := pos;
Display.CopyBlock(F.X + barW + 1, F.Y + d - dY, F.W - barW - 1,
H, F.X + barW + 1, F.Y + F.H - H - dY, Display.replace);
Display.ReplConst(bgd, F.X + barW + 1, F.Y, F.W - barW - 1, F.H - H - dY, Display.replace);
Draw(F, F.Y + F.H - H, F.Y + dY, F.org + (maxline - line + 1)*number);
DrawGreyBars(F)
ELSIF (pos < F.org) & (F.org <= pos + maxline*number) THEN
(* scroll up *)
RemoveCursor(F);
IF F.len DIV number <= maxline THEN (* whole file fits in frame *)
d := F.H - SHORT(F.len DIV number + 1)*fontheight
END;
H := (line + 1)*fontheight;
F.org := pos;
Display.CopyBlock(F.X + barW + 1, F.Y + F.H - H - dY,
F.W - barW - 1, H, F.X + barW + 1, F.Y + d - dY, Display.replace);
Display.ReplConst(bgd, F.X + barW + 1, F.Y + H + d - dY, F.W - barW - 1, F.H - H - d + dY, Display.replace);
Draw(F, F.Y + F.H, F.Y + H + d - 1, F.org);
DrawGreyBars(F)
ELSE
(* redraw whole frame *)
F.org := pos;
DrawFrame(F)
END
END ScrollFrame;
PROCEDURE Scroll (F : Frame; X, Y : INTEGER; keysum : SET);
VAR pos : LONGINT; line, line1, Ybar : INTEGER;
PROCEDURE Underscore (col, mode : INTEGER);
BEGIN
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
Display.ReplConstC(F, col, F.X + begOfLine, Ybar - 3, adrlen*fontwidth, 2, mode)
END Underscore;
PROCEDURE Track (VAR X, Y : INTEGER; VAR keysum : SET);
VAR keys, prim : SET; Y1, oldline : INTEGER;
BEGIN
keys := keysum; prim := keysum;
oldline := -1; Ybar := -1;
WHILE keys # {} DO
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y);
GetLine(F, Y, line);
IF line*number + F.org >= F.len THEN
line := SHORT((F.len - F.org - 1) DIV number)
END;
IF line # oldline THEN
IF ~(MM IN prim) THEN Underscore(bgd, Display.replace) END;
GetY(F, line*number + F.org, Ybar);
IF ~(MM IN prim) THEN Underscore(fgd, Display.replace) END;
oldline := line
END;
Input.Mouse(keys, X, Y);
keysum := keysum + keys
END
END Track;
BEGIN
pos := F.org;
IF MR IN keysum THEN
Track(X, Y, keysum);
IF keysum = {ML, MM, MR} THEN
(* cancel *)
Underscore(bgd, Display.replace);
RETURN
ELSE
(* this line to bottom of frame *)
GetLine(F, F.Y + 1, line1);
pos := F.org - (line1 - line)*number;
IF pos < 0 THEN
IF F.len DIV number > line1 THEN (* whole file fist in frame *)
line := ((line1 + 1)*number - SHORT(F.org)) DIV number - 1
END;
pos := 0
END;
Underscore(bgd, Display.replace)
END
ELSIF MM IN keysum THEN
Track(X, Y, keysum);
IF keysum = {ML, MM, MR} THEN
(* cancel *)
RETURN
ELSIF MR IN keysum THEN
(* scroll to bof *)
pos := 0;
IF pos # F.org THEN F.org := pos; DrawFrame(F); RETURN END
ELSIF ML IN keysum THEN
(* scroll to eof *)
pos := (F.len DIV number - 2)*number (* 2 is heuristic *);
IF pos < 0 THEN pos := 0 END;
IF pos # F.org THEN F.org := pos; DrawFrame(F); RETURN END
ELSE
(* set clip to position *)
pos := (F.Y + F.H - Y)*F.len DIV F.H;
pos := pos DIV number*number;
line := SHORT(pos - F.org) DIV number;
IF line < 0 THEN (* scroll up *)
GetLine(F, F.Y + 1, line1);
IF F.len DIV number > line1 THEN
line := line1 + line
ELSE (* whole file fits in frame *)
line := SHORT(F.len) DIV number + line
END
END
END
ELSIF ML IN keysum THEN
Track(X, Y, keysum);
IF keysum = {ML, MM, MR} THEN
(* cancel *)
Underscore(bgd, Display.replace);
RETURN
ELSE
(* this line to top of frame *)
pos := line*number + F.org;
IF pos > F.len THEN pos := F.len DIV number*number END;
Underscore(bgd, Display.replace)
END
END;
IF F.org # pos THEN ScrollFrame(F, pos, line) END
END Scroll;
(* ______________________________ mouse tracking ____________________________ *)
PROCEDURE TrackMouse (F : Frame; X, Y : INTEGER; VAR keys : SET);
VAR off, line : INTEGER;
track : BOOLEAN;
prim, sec : CursorCoord;
BEGIN
IF ~F.hasCursor & (keys = {ML}) THEN
Oberon.PassFocus(Viewers.This(X, Y));
track := TRUE
ELSIF keys = {ML} THEN
track := TRUE
ELSE
track := FALSE
END;
WHILE keys # {} DO
Input.Mouse(keys, X, Y);
IF (F.X + hmin < X) & (X < F.X + hmax) THEN
prim := hexcurs; sec := asccurs;
ELSIF (F.X + amin < X) & (X < F.X + amax) THEN
prim := asccurs; sec := hexcurs
ELSE
RemoveCursor(F); prim := NIL; sec := NIL;
END;
GetLine(F, Y, line); GetOffset(F, X, off);
IF track THEN
IF (prim # NIL) & ((F.cursor1 # prim) OR (F.org + line*number + off # F.cursorBytePos)) THEN
RemoveCursor(F);
F.cursor1 := prim; F.cursor2 := sec;
SetCursor(F, X, Y)
END
END;
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y)
END
END TrackMouse;
(* ______________________________ edit procedures ____________________________ *)
PROCEDURE CopyFile (F : Frame);
CONST bufSize = 512;
VAR new : Files.File;
writer : Files.Rider;
buf : ARRAY bufSize OF CHAR;
BEGIN
Files.Set(R, F.model.file, 0);
new := Files.New(F.model.name);
Files.Set(writer, new, 0);
Files.ReadBytes(R, buf, bufSize);
WHILE ~R.eof DO
Files.WriteBytes(writer, buf, bufSize);
Files.ReadBytes(R, buf, bufSize)
END;
Files.WriteBytes(writer, buf, bufSize - R.res);
F.model.file := new
END CopyFile;
PROCEDURE Edit (F : Frame; ch : CHAR);
CONST cright = 0C3X; cleft = 0C4X;
VAR hX, aX, Y : INTEGER;
BEGIN
IF F.hasCursor THEN
IF (ch = cright) & (F.cursorBytePos # F.len-1) THEN
InvertCursor(F);
INC(F.cursorBytePos);
GetX(F, F.cursorBytePos, hX, aX); GetY(F, F.cursorBytePos, Y);
IF F.cursor1 = hexcurs THEN SetCursor(F, hX, Y) ELSE SetCursor(F, aX, Y) END
ELSIF (ch = cleft) & (F.cursorBytePos # 0) THEN
InvertCursor(F);
DEC(F.cursorBytePos);
GetX(F, F.cursorBytePos, hX, aX); GetY(F, F.cursorBytePos, Y);
IF F.cursor1 = hexcurs THEN SetCursor(F, hX, Y) ELSE SetCursor(F, aX, Y) END
ELSIF F.cursor1 = hexcurs THEN
IF HexToDec(ch) >= 0 THEN
IF F.virgin THEN F.virgin := FALSE; CopyFile(F) END;
HexUpdateByte(F, HexToDec(ch));
SendUpdateMsg(F);
DrawCursor(F)
END
ELSIF F.cursor1 = asccurs THEN
IF (ch = ".") OR (ReadableChar(ch) # ".") THEN
IF F.virgin THEN F.virgin := FALSE; CopyFile(F) END;
AscUpdateByte(F, ch);
SendUpdateMsg(F);
DrawCursor(F);
IF F.cursorBytePos # F.len-1 THEN
InvertCursor(F);
INC(F.cursorBytePos);
GetX(F, F.cursorBytePos, hX, aX); GetY(F, F.cursorBytePos, Y);
SetCursor(F, aX, Y)
END
END
END
END
END Edit;
(* ______________________________ message handling ____________________________ *)
PROCEDURE Copy (src, dst : Frame);
BEGIN
dst.virgin := src.virgin; dst.hasCursor := FALSE;
dst.cursor1 := NIL; dst.cursor2 := NIL; dst.cursorBytePos := -1;
NEW(dst.model); dst.model := src.model;
dst.org := src.org; dst.len := src.len;
dst.handle := src.handle
END Copy;
PROCEDURE Modify (F : Frame; Y, H : INTEGER);
VAR line, dH : INTEGER;
BEGIN
dH := H - F.H;
IF dH > 0 THEN (* extend *)
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
GetLine(F, F.Y, line);
IF F.Y + F.H # Y + H THEN
Display.CopyBlock(F.X, F.Y, F.W, F.H, F.X, Y + dH, Display.replace)
END;
F.Y := Y; F.H := H;
Display.ReplConst(bgd, F.X, F.Y, F.W, dH, Display.replace);
Display.ReplConst(fgd, F.X + barW, F.Y, 1, dH, Display.replace);
Draw(F, Y + H - line*fontheight, F.Y + dY, F.org + line*number);
DrawGreyBars(F)
ELSIF dH < 0 THEN (* reduce *)
Oberon.RemoveMarks(F.X, F.Y, F.W, F.H);
line := (H -1- dY) DIV fontheight;
IF (line + 1)*fontheight >= H - dY THEN DEC(line) END;
dH := (line + 1)*fontheight;
IF F.Y + F.H # Y + H THEN
Display.CopyBlock(F.X, F.Y + F.H - dH - dY, F.W, dH + dY, F.X, Y + H - dH - dY, Display.replace)
END;
F.Y := Y; F.H := H;
IF dH < 0 THEN dH := 0 END;
Display.ReplConst(bgd, F.X + barW + 1, F.Y, F.W - barW - 1, H - dH - dY, Display.replace);
DrawClip(F);
DrawGreyBars(F)
END
END Modify;
PROCEDURE Handle(F : Display.Frame; VAR M : Display.FrameMsg);
VAR dest : Frame;
BEGIN
WITH F : Frame DO
IF M IS Oberon.InputMsg THEN
WITH M : Oberon.InputMsg DO
IF M.id = Oberon.track THEN
IF M.X < F.X + barW THEN
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, M.X, M.Y);
Scroll(F, M.X, M.Y, M.keys)
ELSE
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, M.X, M.Y);
TrackMouse(F, M.X, M.Y, M.keys)
END
ELSIF M.id = Oberon.consume THEN
Edit(F, M.ch)
END
END
ELSIF M IS MenuViewers.ModifyMsg THEN
WITH M : MenuViewers.ModifyMsg DO
RemoveCursor(F);
Modify(F, M.Y, M.H)
END
ELSIF M IS Oberon.CopyMsg THEN
WITH M : Oberon.CopyMsg DO
IF M.F = NIL THEN NEW(dest); M.F := dest END;
RemoveCursor(F);
Copy(F, M.F(Frame))
END
ELSIF M IS UpdateMsg THEN
WITH M : UpdateMsg DO
IF M.id = changeFont THEN DrawFrame(F)
ELSIF M.id = updateByte THEN
IF M.file = F.model.file THEN
WriteBang(F); Update(F, M.pos, M.ch)
END
END
END
ELSIF M IS Oberon.ControlMsg THEN RemoveCursor(F)
ELSIF M IS CursorMsg THEN
WITH M : CursorMsg DO
IF F.hasCursor THEN
M.file := F.model.file; M.pos := F.cursorBytePos
END
END
END
ELSE (* skip *)
END
END Handle;
(* ______________________ auxiliary procedures StoreTextToFile _________________________ *)
PROCEDURE WriteSpaces (num: INTEGER);
VAR i : INTEGER;
BEGIN
i := 0;
WHILE i < num DO Texts.Write(W, " "); INC(i) END
END WriteSpaces;
PROCEDURE WriteAddress (pos: LONGINT);
VAR div : LONGINT;
BEGIN
div := 0100000H;
REPEAT
Texts.Write(W, DecToHex(pos DIV div));
pos := pos MOD div;
div := ASH(div, -4);
UNTIL div = 0
END WriteAddress;
PROCEDURE WriteHexPart (max: INTEGER);
VAR i : INTEGER;
BEGIN
i := 0;
WHILE i < max DO
Texts.Write(W, DecToHex(ASH(ORD(nextline[i]), -4)));
Texts.Write(W, DecToHex(ORD(nextline[i]) MOD 16));
WriteSpaces(1); INC(i)
END;
WriteSpaces((number-i)*3)
END WriteHexPart;
PROCEDURE WriteAscPart (max : INTEGER);
VAR i : INTEGER;
BEGIN
i := 0;
WHILE i < max DO Texts.Write(W, ReadableChar(nextline[i])); INC(i) END
END WriteAscPart;
PROCEDURE WriteLine (nr : INTEGER; adr : LONGINT);
BEGIN
WriteAddress(adr); WriteSpaces(colspace);
WriteHexPart(nr); WriteSpaces(colspace-1);
WriteAscPart(nr); Texts.WriteLn(W)
END WriteLine;
(* ______________________________ Interface to Hex-Part of Module ____________________________ *)
PROCEDURE OpenFrame (F: Frame; file: Files.File; name: ARRAY OF CHAR; handle: Display.Handler);
BEGIN
F.virgin := TRUE; F.hasCursor := FALSE;
F.cursor1 := NIL; F.cursor2 := NIL;
F.cursorBytePos := -1;
NEW(F.model); F.model.file := file;
COPY(name, F.model.name);
F.org := 0; F.len := Files.Length(file);
F.handle := handle
END OpenFrame;
PROCEDURE StoreFile (F : Frame; name : ARRAY OF CHAR);
BEGIN
F.virgin := TRUE;
DeleteBang(F);
COPY(name, F.model.name);
CopyFile(F);
Files.Register(F.model.file)
END StoreFile;
PROCEDURE StoreTextToFile (F : Frame; name : ARRAY OF CHAR);
VAR T : Texts.Text;
rest : INTEGER;
oldfont : Fonts.Font;
BEGIN
T := TextFrames.Text("");
oldfont := W.fnt;
Texts.SetFont(W, font);
Files.Set(R, F.model.file, 0);
Files.ReadBytes(R, nextline, number);
WHILE ~R.eof DO
WriteLine(number, Files.Pos(R)-number);
Files.ReadBytes(R, nextline, number)
END;
rest := number - SHORT(R.res);
IF rest > 0 THEN WriteLine(rest, Files.Pos(R) - rest) END;
Texts.Append(T, W.buf);
Texts.Close(T, name);
Texts.SetFont(W, oldfont);
END StoreTextToFile;
PROCEDURE ChangeFont (name: ARRAY OF CHAR; VAR res: INTEGER);
VAR newfont : Fonts.Font;
M : UpdateMsg;
dx1, dx2, x, y, w, h : INTEGER;
p : Display.Pattern;
BEGIN
newfont := Fonts.This(name);
IF name # Fonts.Default.name THEN
IF (Fonts.Default = newfont) OR (newfont = NIL) THEN
res := 1; (* font not found *)
RETURN
END
END;
Display.GetChar(newfont.raster, "W", dx1, x, y, w, h, p);
Display.GetChar(newfont.raster, "i", dx2, x, y, w, h, p);
IF dx1 # dx2 THEN
res := 2 (* not a non-proportional font *)
ELSE
res := 0; (* ok *)
font := newfont;
InitDisplayVars;
M.id := changeFont;
Viewers.Broadcast(M)
END
END ChangeFont;
PROCEDURE SearchPat (F: Frame; pat: ARRAY OF CHAR; len: INTEGER);
VAR org, pos, cursorpos: LONGINT; ch: CHAR; patpos: INTEGER;
hX, aX, Y: INTEGER;
BEGIN
IF F.hasCursor THEN pos := F.cursorBytePos ELSE pos := 0 END;
REPEAT
Files.Set(R, F.model.file, pos); Files.Read(R, ch);
WHILE ~R.eof & (ch # pat[0]) DO Files.Read(R, ch) END;
IF ch = pat[0] THEN pos := Files.Pos(R); Files.Read(R, ch); patpos := 1;
WHILE (patpos < len) & (ch = pat[patpos]) DO Files.Read(R, ch); INC(patpos) END;
IF patpos = len THEN (* pattern found *)
IF ~F.hasCursor THEN Oberon.PassFocus(Viewers.This(F.X, F.Y)) END;
cursorpos := pos + len - 1;
org := ((cursorpos DIV number) - 1) * number;
IF org < 0 THEN org := 0 END;
F.org := org; DrawFrame(F);
F.cursor1 := asccurs; F.cursor2 := hexcurs;
GetX(F, cursorpos, hX, aX); GetY(F, cursorpos, Y);
SetCursor(F, aX, Y);
RETURN;
END
END
UNTIL R.eof;
RemoveCursor(F);
END SearchPat;
(* _________________________________________ Command Part _____________________________________ *)
PROCEDURE GetFrame (VAR F : Frame; VAR name : ARRAY OF CHAR);
VAR par : Oberon.ParList; V : Viewers.Viewer; S : Texts.Scanner;
BEGIN
par := Oberon.Par;
IF par.frame = par.vwr.dsc THEN V := par.vwr;
ELSE V := Oberon.MarkedViewer();
END;
Texts.OpenScanner(S, V.dsc(TextFrames.Frame).text, 0); Texts.Scan(S);
IF (S.class = Texts.Name) & (V.dsc # NIL) & (V.dsc.next IS Frame) THEN
F := V.dsc.next(Frame); COPY(S.s, name)
ELSE F := NIL
END
END GetFrame;
PROCEDURE GetName (VAR name: ARRAY OF CHAR);
VAR T: Texts.Text; S: Texts.Scanner; beg, end, time: LONGINT;
BEGIN
Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S);
IF (S.class = Texts.Char) & (S.c = "^") THEN
Oberon.GetSelection(T, beg, end, time);
IF time >= 0 THEN Texts.OpenScanner(S, T, beg); Texts.Scan(S) END;
END;
IF S.class = Texts.Name THEN COPY(S.s, name)
ELSE name[0] := 0X;
END
END GetName;
PROCEDURE FontLogText (name: ARRAY OF CHAR; res : INTEGER);
BEGIN
Texts.WriteString(W, name);
IF res = 1 THEN Texts.WriteString(W, " not found");
ELSIF res = 2 THEN Texts.WriteString(W, " is not a fixed-width font")
END;
Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
END FontLogText;
PROCEDURE SetRider (VAR done : BOOLEAN);
VAR M: CursorMsg;
BEGIN
M.pos := -1;
Viewers.Broadcast(M);
IF M.pos >= 0 THEN Files.Set(R, M.file, M.pos); done := TRUE
ELSE done := FALSE
END
END SetRider;
PROCEDURE Open*;
VAR F: Frame; M: TextFrames.Frame; V: Viewers.Viewer; T: Texts.Text; buf: Texts.Buffer;
File: Files.File; X, Y: INTEGER;
name: ARRAY 32 OF CHAR; res: INTEGER;
BEGIN
GetName(name);
IF name # "" THEN
File := Files.Old(name);
IF File # NIL THEN NEW(F);
OpenFrame(F, File, name, Handle);
IF Files.Old("Hex.Menu.Text") = NIL THEN M := TextFrames.NewMenu(name, StandardMenu)
ELSE M := TextFrames.NewMenu(name, "");
NEW(T); Texts.Open(T, "Hex.Menu.Text");
NEW(buf); Texts.OpenBuf(buf); Texts.Save(T, 0, T.len, buf); Texts.Append(M.text, buf)
END;
Oberon.AllocateUserViewer(Oberon.Mouse.X, X, Y);
V := MenuViewers.New(M, F, TextFrames.menuH, X, Y);
ELSE
Texts.WriteString(W, name); Texts.WriteString(W, " not found"); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END
END Open;
PROCEDURE Store*;
VAR F: Frame; name: ARRAY 32 OF CHAR;
PROCEDURE Backup (VAR name: ARRAY OF CHAR);
VAR res, i: INTEGER; bak: ARRAY 32 OF CHAR;
BEGIN
i := 0;
WHILE name[i] # 0X DO bak[i] := name[i]; INC(i) END;
bak[i] := "."; bak[i+1] := "B"; bak[i+2] := "a"; bak[i+3] := "k";
bak[i+4] := 0X;
Files.Rename(name, bak, res);
END Backup;
BEGIN
GetFrame(F, name);
IF F # NIL THEN
Texts.WriteString(W, "Hex.Store "); Texts.Append(Oberon.Log, W.buf);
Backup(name);
StoreFile(F, name);
Texts.WriteString(W, name);
Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf);
END
END Store;
PROCEDURE StoreText*;
VAR F: Frame; name: ARRAY 32 OF CHAR;
PROCEDURE NewName (VAR name : ARRAY OF CHAR);
VAR i : INTEGER;
BEGIN i := 0;
WHILE name[i] # 0X DO INC(i) END;
name[i] := "."; name[i+1] := "T"; name[i+2] := "e"; name[i+3] := "x"; name[i+4] := "t";
name[i+5] := 0X;
END NewName;
BEGIN
GetFrame(F, name);
IF F # NIL THEN
Texts.WriteString(W, "Hex.StoreText "); Texts.Append(Oberon.Log, W.buf);
NewName(name);
StoreTextToFile(F, name);
Texts.WriteString(W, name); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf);
END
END StoreText;
PROCEDURE SetFont*;
VAR res : INTEGER;
name : ARRAY 32 OF CHAR;
BEGIN
GetName(name);
IF name # "" THEN
ChangeFont(name, res);
IF res # 0 THEN FontLogText(name, res) END
END
END SetFont;
PROCEDURE GetSInt*;
VAR x : CHAR; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.Read(R, x);
Texts.WriteString(W, "SHORTINT"); Texts.Write(W, 09X);
Texts.WriteInt(W, ORD(x), 0); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END;
END GetSInt;
PROCEDURE GetInt*;
VAR x : INTEGER; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.ReadInt(R, x);
Texts.WriteString(W, "INTEGER"); Texts.Write(W, 09X);
Texts.WriteInt(W, x, 0); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetInt;
PROCEDURE GetLInt*;
VAR x : LONGINT; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.ReadLInt(R, x);
Texts.WriteString(W, "LONGINT"); Texts.Write(W, 09X);
Texts.WriteInt(W, x, 0); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetLInt;
PROCEDURE GetReal*;
VAR x : REAL; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.ReadReal(R, x);
Texts.WriteString(W, "REAL"); Texts.Write(W, 09X);
Texts.WriteReal(W, x, 20); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetReal;
PROCEDURE GetLReal*;
VAR x : LONGREAL; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.ReadLReal(R, x);
Texts.WriteString(W, "LONGREAL"); Texts.Write(W, 09X);
Texts.WriteLongReal(W, x, 20); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetLReal;
PROCEDURE GetNum*;
VAR x, n : LONGINT; done : BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
n := Files.Pos(R);
Files.ReadNum(R, x);
n := Files.Pos(R) - n;
Texts.WriteString(W, "Number ("); Texts.WriteInt(W, n, 0);
IF n > 1 THEN Texts.WriteString(W, " Bytes)") ELSE Texts.WriteString(W, " Byte)") END;
Texts.Write(W, 09X);
Texts.WriteInt(W, x, 0); Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetNum;
PROCEDURE GetSet*;
VAR x : SET; done : BOOLEAN; i, last : SHORTINT;
BEGIN
SetRider(done);
IF done THEN
Files.ReadSet(R, x);
Texts.WriteString(W, "SET"); Texts.Write(W, 09X); Texts.Write(W, "{");
i := 0; last := -1;
REPEAT
IF i IN x THEN
IF last >= 0 THEN Texts.WriteInt(W, last, 0); Texts.Write(W, ",") END;
last := i;
END;
INC(i)
UNTIL (i = 32);
IF last >= 0 THEN Texts.WriteInt(W, last, 0) END;
Texts.Write(W, "}");
Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetSet;
PROCEDURE GetBool*;
VAR x: CHAR; done: BOOLEAN;
BEGIN
SetRider(done);
IF done THEN
Files.Read(R, x);
Texts.WriteString(W, "BOOLEAN"); Texts.Write(W, 09X);
IF x = 01X THEN Texts.WriteString(W, "TRUE")
ELSE Texts.WriteString(W, "FALSE")
END;
Texts.WriteLn(W);
Texts.Append(Oberon.Log, W.buf)
END
END GetBool;
PROCEDURE Search*;
VAR F: Frame; name: ARRAY 32 OF CHAR; ch: CHAR;
T: Texts.Text; beg, end, time: LONGINT; R: Texts.Reader; len: INTEGER;
BEGIN
GetFrame(F, name);
IF F # NIL THEN
Oberon.GetSelection(T, beg, end, time);
IF time > 0 THEN
Texts.OpenReader(R, T, beg); Texts.Read(R, ch); len := 0;
WHILE (len <= LEN(name)) & (Texts.Pos(R) <= end) DO
name[len] := ch; INC(len); Texts.Read(R, ch);
END;
SearchPat(F, name, len);
END;
END
END Search;
BEGIN
Texts.OpenWriter(W);
ChangeFont(DefaultFont, res);
IF res # 0 THEN
FontLogText(DefaultFont, res); HALT(99)
END Hex.